﻿using System;
using System.Collections.Generic;

namespace DenisVuyka.Controls.PropertyGrid
{
  using Data;

  public abstract class DisplaySchema<T>
      where T : PropertyItem
  {
    #region Properties
    private readonly HashSet<Func<T, bool>> conditions = new HashSet<Func<T, bool>>();
    public IEnumerable<Func<T, bool>> Conditions
    {
      get
      {
        foreach (Func<T, bool> condition in conditions)
          yield return condition;
      }
    }

    private DisplaySchemaModes mode = DisplaySchemaModes.Inclusive;
    public DisplaySchemaModes Mode
    {
      get { return mode; }
      set { mode = value; }
    }

    public bool IsEmpty
    {
      get { return conditions.Count == 0; }
    }
    #endregion

    #region ctor

    public DisplaySchema() { }

    public DisplaySchema(DisplaySchemaModes mode)
    {
      this.mode = mode;
    }

    #endregion

    #region Public API
    public bool AddCondition(Func<T, bool> condition)
    {
      return conditions.Add(condition);
    }

    public bool ContainsCondition(Func<T, bool> condition)
    {
      return conditions.Contains(condition);
    }

    public bool RemoveCondition(Func<T, bool> condition)
    {
      return conditions.Remove(condition);
    }

    public void Reset()
    {
      conditions.Clear();
    }

    public bool Evaluate(T target)
    {
      switch (mode)
      {
        case DisplaySchemaModes.Inclusive:
          return EvaluateInclusive(target);

        case DisplaySchemaModes.Exclusive:
          return EvaluateExclusive(target);

        default:
          throw new NotSupportedException();
      }
    }
    #endregion

    #region Private methods

    private bool EvaluateInclusive(T target)
    {
      foreach (Func<T, bool> func in conditions)
        if (func(target)) return true;

      return false;
    }

    private bool EvaluateExclusive(T target)
    {
      foreach (Func<T, bool> func in conditions)
        if (!func(target)) return false;

      return true;
    }

    #endregion
  }
}
